﻿using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using System;
using System.Net;
using System.Threading.Tasks;
using Loong.AspNetCore.Models;
using Loong.AspNetCore.Mvc.Extensions;
using Loong.AspNetCore.Mvc.Results;
using Loong.Authorization;
using Loong.Extensions;
using Loong.Logging;
using Loong.Runtime.Security;

namespace Loong.AspNetCore.Mvc.Authorization
{
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
    public class PermissionFilterAttribute : Attribute, IAsyncAuthorizationFilter
    {
        public string[] Permissions { get; }

        public PermissionFilterAttribute(params string[] permissions)
        {
            Permissions = permissions;
        }

        public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
        {
            ILogger logger = context.HttpContext.RequestServices.GetService<ILogger<PermissionFilterAttribute>>();
            IErrorInfoBuilder errorInfoBuilder = context.HttpContext.RequestServices.GetService<IErrorInfoBuilder>();

            try
            {
                var userId = context.HttpContext.User?.FindFirst(LoongClaimTypes.UserId)?.Value;
                if (!userId.IsNullOrEmpty())
                {
                    var permissionChecker = context.HttpContext.RequestServices.GetRequiredService<IPermissionChecker>();
                    foreach (var permission in Permissions)
                    {
                        if (await permissionChecker.IsGrantedAsync(userId.To<long>(), permission))
                        {
                            return;
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                logger?.LogException(ex);

                if (ActionResultHelper.IsObjectResult(context.ActionDescriptor.GetMethodInfo().ReturnType))
                {
                    context.Result = new ObjectResult(new AjaxResponse(errorInfoBuilder?.BuildForException(ex)))
                    {
                        StatusCode = (int)HttpStatusCode.InternalServerError
                    };
                }
                else
                {
                    context.Result = new StatusCodeResult((int)HttpStatusCode.InternalServerError);
                }
            }

            if (ActionResultHelper.IsObjectResult(context.ActionDescriptor.GetMethodInfo().ReturnType))
            {
                context.Result = new ObjectResult(new AjaxResponse(new ErrorInfo("没有权限进行此操作"), true))
                {
                    StatusCode = context.HttpContext.User.Identity.IsAuthenticated
                        ? (int)HttpStatusCode.Forbidden
                        : (int)HttpStatusCode.Unauthorized
                };
            }
            else
            {
                context.Result = new ChallengeResult();
            }
        }
    }
}
